#include <qapplication.h>
#include <qdialog.h>
#include <qpushbutton.h>
#include <qstring.h>
#include <qdebug.h>
#include <QTime>
#include <QLabel>
#include <QMessageBox>
#include<QFile>

#include "parameters.h"
#include "math.h"


#include "SudokuData.h"
#include "SudokuEnvironment.h"
#include "Chromosome.h"

#include "TournamentSelectionStrategy.h"
#include "RouletteWheelSelectionStrategy.h"
#include "SimpleSelectionStrategy.h"
#include "SelectionStrategyFactory.h"

int main(int argc, char* argv[])
{
    QApplication app(argc, argv);

    QString str = "";

    //QString filePathSudoku("/home/lukasz/magisterka/sudoku/wygenerowane/");
    QString filePathSudoku("../data/");//("/home/lukasz/magisterka/sudoku/test/");//("./");//("/home/lukasz/magisterka/sudoku/Sudoku/");//("./");
    //QString fileNameSudoku("romb3.sss");//("sudoku_2.sss");//("sudoku_test_16.sss");
    //QString fileNameSudoku("sudoku_test_16.sss");
    QString fileNameSudoku("1.sud");
    //QString fileNameSudoku("sudoku_test_16.sss");

    SudokuData sud1(filePathSudoku,fileNameSudoku);//(sudStr);

    qDebug() << sud1;

    bool foundRun;

    do{

        foundRun = false;
        while(sud1.findNakedSingles())
        {
            sud1.excludeAllPossibl();
            foundRun = true;
        }

        while(sud1.findHiddenSingles())
        {
            sud1.excludeAllPossibl();
            foundRun = true;
        }
        qDebug() << "foundRun:" << foundRun;

    }while(foundRun == true);

    //sud1.findHiddenSingles();
    //sud1.findNakedSingles();
    //sud1.excludeAllPossibl();


    qDebug() << sud1;
    qDebug() << "possibleSolutions: " << sud1.countPossibleSolutions();
    //qDebug() << sud1.cells.size();

    int popSize = 300;
    int selection = Tournament;//Deterministic;//RouletteWheel;
    bool adjustFit = true;//false;
    double crossProb = 0.5;
    double mutProb = 0.05;
    double additionalOpProb1 = 0.03;//9999;
    int tournamentSize = 10;
    bool replaceWorst = true;
    int addFresh = 4;
    int eliminateDuplicates = Replace;
    int finishCond = BestFitnessKnown;//GenerationCount;

    int generationCount = 1;
    int runNumber = 1;

    QString fileName = "sudoku.txt";
    QFile* file = new QFile (fileName );

    if ( !file->open ( QIODevice::Append | QIODevice::Text ) )
        qFatal("cannot open file");

    QTextStream stream(file);

    stream << endl;
    stream << endl;

    stream << "popSize: " << popSize;
    stream << " selection: " << selection;
    stream << " adjustFit: " << adjustFit;
    stream << " crossProb: " << crossProb;
    stream << " mutProb: " << mutProb;
    stream << " additionalOpProb1: " << additionalOpProb1;
    stream << " tournamentSize: " << tournamentSize;
    stream << " replaceWorst: " << replaceWorst;
    stream << " addFresh: " << addFresh;
    stream << " eliminateDuplicates: " << eliminateDuplicates;
    stream << " runNumber: " << runNumber;
    stream << " generationCount: " << generationCount;
    stream << " finishCond: " << finishCond;
    stream << " fileName: " << fileNameSudoku;
    stream << endl;

    int sumOfAge = 0;
    QList<int> ageList;

    for(int i=0;i<runNumber;++i)
    {
        SelectionStrategy* selectionStrategy = SelectionStrategyFactory::getStrategy(selection);
        if(selection == Tournament)
            dynamic_cast<TournamentSelectionStrategy*>(selectionStrategy)->setSize(tournamentSize);


        SudokuEnvironment sudEnv(popSize, sud1);
        sudEnv.setMaxGenerationsCount(generationCount);
        sudEnv.setSelectionStrategy(selectionStrategy);
        sudEnv.setMutationProb(mutProb);
        sudEnv.setAdditionalOperatorProb1(additionalOpProb1);
        sudEnv.setAddFreshChromosomes(addFresh);
        sudEnv.setRemoveDuplicatesMethod(eliminateDuplicates);
        sudEnv.setFinishConditionType(finishCond);

        sudEnv.setAdjustFitness(adjustFit);
        sudEnv.setCrossoverProb(crossProb);
        sudEnv.setReplaceWorstRepresentative(replaceWorst);
        //environment.setAbortWorseGenerations(true);


        sudEnv.startSimulation();
        qDebug() << *sudEnv.getSolution();

        str += "age: " + QString::number(sudEnv.getAge()) + "\n";
        str += sudEnv.decodeChromosome(*sudEnv.getSolution()) + "\n";
        //str += "time: " +  QString::number(timeElapsed, 'g');
        //str += "generations/second: " +  QString::number(sudEnv.getPopulationAge()/timeElapsed, 'g');

        stream << sudEnv.getAge() << ";";
        sumOfAge += sudEnv.getAge();
        ageList.append(sudEnv.getAge());

        qDebug() << "run: " << runNumber;
        qDebug() << "i: " << i;

        sudEnv.decodeChromosome(*sudEnv.getSolution());

        sleep(1);//not working in windows

    }
    qDebug() << "possibleSolutions: " << sud1.countPossibleSolutions();


    double average = sumOfAge/(double)runNumber;

    //wariancja

    double sumSq = 0;
    for(int a=0;a<ageList.size();++a)
    {
        sumSq += (ageList.at(a) - average) * (ageList.at(a) - average);
    }
    double wariancja = sumSq/runNumber;
    double odchylenie = sqrt(wariancja);


    stream << endl;
    stream << "GEN av: " << average << " wariancja: " << wariancja << " odchylenie: " << odchylenie << endl;
    file->close ();


    QMessageBox* messageBox = new QMessageBox();
    messageBox->setText(str);
    messageBox->show();


    return 0;//app.exec();
}

